﻿
Imports System.Runtime.InteropServices

Partial Public Class convertor
    Private Shared Function valid(Of T)(ByVal b() As Byte,
                                        ByVal io As T,
                                        ByVal offset As Int32,
                                        ByRef sz As Int32) As Boolean
        Return Not b Is Nothing AndAlso offset >= 0 AndAlso eva(sz, sizeof(io)) AndAlso b.Length() >= offset + sz
    End Function

    Private Delegate Sub tobytesWriter(Of t)(ByVal ptr As Object, ByVal offset As Int32, ByVal value As t)

    Private Shared Function tobytesImpl(Of t)(ByVal i As t,
                                              ByVal b() As Byte,
                                              ByRef offset As Int32,
                                              ByVal writer As tobytesWriter(Of t)) As Boolean
        assert(Not writer Is Nothing)
        Dim sz As Int32 = 0
        If valid(b, i, offset, sz) Then
            writer(b, offset, i)
            offset += sz
            Return True
        Else
            Return False
        End If
    End Function

    Private Shared Function init_tobytes(Of t)(ByVal i As t, ByRef b As bytes) As Boolean
        If b Is Nothing Then
            b = New bytes()
        End If
        If b.size() <> sizeof(i) Then
            b.size() = sizeof(i)
        End If
        Return True
    End Function

    Public Shared Function tobytes(ByVal i As Byte, ByVal b() As Byte, Optional ByRef offset As Int32 = 0) As Boolean
        Return tobytesImpl(i, b, offset, AddressOf Marshal.WriteByte)
    End Function

    Public Shared Function tobytes(ByVal i As Byte, ByRef b As bytes) As Boolean
        Return init_tobytes(i, b) AndAlso tobytes(i, +b)
    End Function

    Public Shared Function tobytes(ByVal i As Int16, ByVal b() As Byte, Optional ByRef offset As Int32 = 0) As Boolean
        Return tobytesImpl(i, b, offset, AddressOf Marshal.WriteInt16)
    End Function

    Public Shared Function tobytes(ByVal i As Int16, ByRef b As bytes) As Boolean
        Return init_tobytes(i, b) AndAlso tobytes(i, +b)
    End Function

    Public Shared Function tobytes(ByVal i As Int32, ByVal b() As Byte, Optional ByRef offset As Int32 = 0) As Boolean
        Return tobytesImpl(i, b, offset, AddressOf Marshal.WriteInt32)
    End Function

    Public Shared Function tobytes(ByVal i As Int32, ByRef b As bytes) As Boolean
        Return init_tobytes(i, b) AndAlso tobytes(i, +b)
    End Function

    Public Shared Function tobytes(ByVal i As Int64, ByVal b() As Byte, Optional ByRef offset As Int32 = 0) As Boolean
        Return tobytesImpl(i, b, offset, AddressOf Marshal.WriteInt64)
    End Function

    Public Shared Function tobytes(ByVal i As Int64, ByRef b As bytes) As Boolean
        Return init_tobytes(i, b) AndAlso tobytes(i, +b)
    End Function

    Public Shared Function tobytes(ByVal i As Int32) As bytes
        Dim o As bytes = Nothing
        If tobytes(i, o) Then
            Return o
        Else
            'this call should not fail, so debugassert here
            debugassert(False, "cannot convert int32 " + Convert.ToString(i) + " to bytes.")
            Return Nothing
        End If
    End Function

    Public Shared Function tobytes(ByVal i As Int64) As bytes
        Dim o As bytes = Nothing
        If tobytes(i, o) Then
            Return o
        Else
            'this call should not fail, so debugassert here
            debugassert(False, "cannot convert int64 " + Convert.ToString(i) + " to bytes.")
            Return Nothing
        End If
    End Function

#If RETIRED Then
        Private Shared Function tobyteArrayImpl(Of t)(ByVal i As t, ByRef b() As Byte _
                                            , ByRef writer As tobytesWriter(Of t)) As Boolean
            If b Is Nothing OrElse b.Length() <> sizeof(i) Then
                ReDim b(sizeof(i) - 1)
            End If
            writer(b, 0, i)
            Return True
        End Function

        Public Shared Function tobyteArray(ByVal i As Byte, ByRef b() As Byte) As Boolean
            Return tobyteArrayImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteByte)
        End Function

        Public Shared Function tobyteArray(ByVal i As Int16, ByRef b() As Byte) As Boolean
            Return tobyteArrayImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt16)
        End Function

        Public Shared Function tobyteArray(ByVal i As Int32, ByRef b() As Byte) As Boolean
            Return tobyteArrayImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt32)
        End Function

        Public Shared Function tobyteArray(ByVal i As Int64, ByRef b() As Byte) As Boolean
            Return tobyteArrayImpl(i, b, AddressOf System.Runtime.InteropServices.Marshal.WriteInt64)
        End Function
#End If

    Private Delegate Function frombyteReader(Of t)(ByVal ptr As Object, ByVal offset As Int32) As t

    Private Shared Function frombytesImpl(Of t)(ByVal b() As Byte,
                                                ByRef offset As Int32,
                                                ByRef o As t,
                                                ByVal reader As frombyteReader(Of t)) As Boolean
        assert(Not reader Is Nothing)
        Dim sz As Int32 = 0
        If valid(b, o, offset, sz) Then
            o = reader(b, offset)
            offset += sz
            Return True
        Else
            Return False
        End If
    End Function

    Private Shared Function init_frombytes(Of T)(ByVal b As bytes, ByVal o As T) As Boolean
        Return Not b Is Nothing AndAlso b.size() >= sizeof(o)
    End Function

    Public Shared Function tobyte(ByVal b() As Byte, ByRef o As Byte, Optional ByRef offset As Int32 = 0) As Boolean
        Return frombytesImpl(b, offset, o, AddressOf Marshal.ReadByte)
    End Function

    Public Shared Function tobyte(ByVal b As bytes, ByRef o As Byte) As Boolean
        Return init_frombytes(b, o) AndAlso tobyte(+b, o)
    End Function

    Public Shared Function toint8(ByVal b() As Byte, ByRef o As Byte, Optional ByRef offset As Int32 = 0) As Boolean
        Return tobyte(b, o, offset)
    End Function

    Public Shared Function toint8(ByVal b As bytes, ByRef o As Byte) As Boolean
        Return tobyte(b, o)
    End Function

    Public Shared Function toint16(ByVal b() As Byte, ByRef o As Int16, Optional ByRef offset As Int32 = 0) As Boolean
        Return frombytesImpl(b, offset, o, AddressOf Marshal.ReadInt16)
    End Function

    Public Shared Function toint16(ByVal b As bytes, ByRef o As Int16) As Boolean
        Return init_frombytes(b, o) AndAlso toint16(+b, o)
    End Function

    Public Shared Function toint32(ByVal b() As Byte, ByRef o As Int32, Optional ByRef offset As Int32 = 0) As Boolean
        Return frombytesImpl(b, offset, o, AddressOf Marshal.ReadInt32)
    End Function

    Public Shared Function toint32(ByVal b As bytes, ByRef o As Int32) As Boolean
        Return init_frombytes(b, o) AndAlso toint32(+b, o)
    End Function

    Public Shared Function toint64(ByVal b() As Byte, ByRef o As Int64, Optional ByRef offset As Int32 = 0) As Boolean
        Return frombytesImpl(b, offset, o, AddressOf Marshal.ReadInt64)
    End Function

    Public Shared Function toint64(ByVal b As bytes, ByRef o As Int64) As Boolean
        Return init_frombytes(b, o) AndAlso toint64(+b, o)
    End Function
End Class
